﻿// -----------------------------------------------------------------------
// <copyright file="HistoOperation.cs" company="FCIS">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace IPPackage.ImageOperation
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class HistoOperation : Operation
    {
        /// <summary>
        /// Gets the min value in array.
        /// </summary>
        /// <param name="data">The data array.</param>
        /// <returns>the min. value</returns>
        public int GetMin(long[] data)
        {
            int min = data.Length;
            try
            {
                for (int i = 0; i < data.Length; i++)
                {
                    if (data[i] > 0)
                    {
                        return i;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }

            return min;
        }

        /// <summary>
        /// Gets the max value in array.
        /// </summary>
        /// <param name="data">The data array.</param>
        /// <returns>the max. value</returns>
        public int GetMax(long[] data)
        {
            int max = 0;
            try
            {
                for (int i = 0; i < data.Length; i++)
                {
                    if (data[i] > 0)
                    {
                        max = i;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }

            return max;
        }

        /// <summary>
        /// Britnesses the specified image.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <returns>NEW IMAGE</returns>
        public Bitmap Britness(int offset)
        {
            Bitmap new_ima;
            try
            {
                this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                new_ima = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        Color temp = this.BufferOfImage[j, i];
                        int red = (int)temp.R + offset;
                        int green = (int)temp.G + offset;
                        int blue = (int)temp.B + offset;
                        if (red > 255)
                        {
                            red = 255;
                        }
                        else if (red < 0)
                        {
                            red = 0;
                        }

                        if (green > 255)
                        {
                            green = 255;
                        }
                        else if (green < 0)
                        {
                            green = 0;
                        }

                        if (blue > 255)
                        {
                            blue = 255;
                        }
                        else if (blue < 0)
                        {
                            blue = 0;
                        }

                        this.NewBufferOfImage[j, i] = Color.FromArgb(red, green, blue);
                        new_ima.SetPixel(j, i, Color.FromArgb(red, green, blue));
                    }
                }

                return new_ima;
            }
            catch (Exception ex)
            {
                new_ima = null;
                Logger.LogException(ex);
            }

            return new_ima;
        }

        /// <summary>
        /// Gammas the specified image.
        /// </summary>
        /// <param name="gamma">The gamma value.</param>
        /// <returns>new image</returns>
        public Bitmap Gamma(float gamma)
        {
            double[,] gammaRedBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double[,] gammaGreenBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double[,] gammaBlueBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            double red_max = -1, green_max = -1, blue_max = -1, red_min = 256, green_min = 256, blue_min = 256;
            for (int i = 0; i < BufferOfImage.GetLength(1); i++)
            {
                for (int j = 0; j < BufferOfImage.GetLength(0); j++)
                {
                    Color temp = BufferOfImage[j, i];
                    gammaRedBuffer[j, i] = Math.Pow(temp.R, gamma);
                    gammaGreenBuffer[j, i] = Math.Pow(temp.G, gamma);
                    gammaBlueBuffer[j, i] = Math.Pow(temp.B, gamma);
                    if (gammaRedBuffer[j, i] > red_max)
                    {
                        red_max = gammaRedBuffer[j, i];
                    }

                    if (gammaRedBuffer[j, i] < red_min)
                    {
                        red_min = gammaRedBuffer[j, i];
                    }

                    if (gammaGreenBuffer[j, i] > green_max)
                    {
                        green_max = gammaGreenBuffer[j, i];
                    }

                    if (gammaGreenBuffer[j, i] < green_min)
                    {
                        green_min = gammaGreenBuffer[j, i];
                    }

                    if (gammaBlueBuffer[j, i] > blue_max)
                    {
                        blue_max = gammaBlueBuffer[j, i];
                    }

                    if (gammaBlueBuffer[j, i] < blue_min)
                    {
                        blue_min = gammaBlueBuffer[j, i];
                    }
                }
            }

            return this.Normalization(gammaRedBuffer, gammaGreenBuffer, gammaBlueBuffer, red_min, red_max, green_min, green_max, blue_min, blue_max);
        }

        /// <summary>
        /// Normalizations the specified gamma result.
        /// </summary>
        /// <param name="gammaRedBuffer">The gamma of red color for each pixels.</param>
        /// <param name="gammaGreenBuffer">The gamma of green color for each pixels.</param>
        /// <param name="gammaBlueBuffer">The gamma of blue color for each pixels.</param>
        /// <param name="red_min">The red_min.</param>
        /// <param name="red_max">The red_max.</param>
        /// <param name="green_min">The green_min.</param>
        /// <param name="green_max">The green_max.</param>
        /// <param name="blue_min">The blue_min.</param>
        /// <param name="blue_max">The blue_max.</param>
        /// <returns>new image after applying gamma</returns>
        public Bitmap Normalization(double[,] gammaRedBuffer, double[,] gammaGreenBuffer, double[,] gammaBlueBuffer, double red_min, double red_max, double green_min, double green_max, double blue_min, double blue_max)
        {
            this.NewBufferOfImage = new Color[gammaBlueBuffer.GetLength(0), gammaBlueBuffer.GetLength(1)];
            Bitmap new_Img = new Bitmap(gammaBlueBuffer.GetLength(0), gammaBlueBuffer.GetLength(1));
            for (int i = 0; i < gammaBlueBuffer.GetLength(1); i++)
            {
                for (int j = 0; j < gammaBlueBuffer.GetLength(0); j++)
                {
                    double blue = ((gammaBlueBuffer[j, i] - blue_min) / (blue_max - blue_min)) * 255;
                    double red = ((gammaRedBuffer[j, i] - red_min) / (red_max - red_min)) * 255;
                    double green = ((gammaGreenBuffer[j, i] - green_min) / (green_max - green_min)) * 255;
                    this.NewBufferOfImage[j, i] = Color.FromArgb((int)red, (int)green, (int)blue);
                    new_Img.SetPixel(j, i, Color.FromArgb((int)red, (int)green, (int)blue));
                }
            }

            return new_Img;
        }

        /// <summary>
        /// Contrasts the specified offset.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <param name="gragh">The gragh.</param>
        /// <returns>the new image</returns>
        public Bitmap Contrast(int offset, Histogram gragh)
        {
            long[] histogram = gragh.HistoGray();
            double oldMax = this.GetMax(histogram);
            double oldMin = this.GetMin(histogram);
            int newMax = (int)oldMax + (offset / 2);
            int newMin = (int)oldMin - (offset / 2);
            if (newMax > 255)
            {
                newMax = 255;
            }
            else if (newMin < 0)
            {
                newMin = 0;
            }

            this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
            Bitmap newImage = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
            for (int i = 0; i < newImage.Height; i++)
            {
                for (int j = 0; j < newImage.Width; j++)
                {
                    Color temp = this.BufferOfImage[j, i];
                    double red = ((((int)temp.R - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
                    double green = ((((int)temp.G - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
                    double blue = ((((int)temp.B - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
                    if (red > 255)
                    {
                        red = 255;
                    }
                    else if (red < 0)
                    {
                        red = 0;
                    }

                    if (green > 255)
                    {
                        green = 255;
                    }
                    else if (green < 0)
                    {
                        green = 0;
                    }

                    if (blue > 255)
                    {
                        blue = 255;
                    }
                    else if (blue < 0)
                    {
                        blue = 0;
                    }

                    this.NewBufferOfImage[j, i] = Color.FromArgb((int)red, (int)green, (int)blue);
                    newImage.SetPixel(j, i, Color.FromArgb((int)red, (int)green, (int)blue));
                }
            }

            return newImage;
        }

        /// <summary>
        /// Equalizations image.
        /// </summary>
        /// <returns>new image</returns>
        public Bitmap Equalization()
        {
            Histogram his = new Histogram();
            his.BufferOfImage = this.BufferOfImage;
            long[] red = his.HistoRed();
            long[] green = his.HistoGreen();
            long[] blue = his.HistoBlue();
            long redMax = this.GetMax(red);
            long greenMax = this.GetMax(green);
            long blueMax = this.GetMax(blue);
            double[] redCumm = new double[redMax + 1];
            double[] greenCumm = new double[greenMax + 1];
            double[] blueCumm = new double[blueMax + 1];
            int i;
            if (blueMax > greenMax)
            {
                if (redMax > blueMax)
                {
                    i = (int)redMax;
                }
                else
                {
                    i = (int)blueMax;
                }
            }
            else
            {
                if (redMax > greenMax)
                {
                    i = (int)redMax;
                }
                else
                {
                    i = (int)greenMax;
                }
            }

            for (int j = 0; j <= i; j++)
            {
                if (j <= redMax)
                {
                    if (j == 0)
                    {
                        redCumm[j] = red[j];
                    }
                    else
                    {
                        redCumm[j] = redCumm[j - 1] + red[j];
                    }
                }

                if (j <= greenMax)
                {
                    if (j == 0)
                    {
                        greenCumm[j] = green[j];
                    }
                    else
                    {
                        greenCumm[j] = greenCumm[j - 1] + green[j];
                    }
                }

                if (j <= blueMax)
                {
                    if (j == 0)
                    {
                        blueCumm[j] = blue[j];
                    }
                    else
                    {
                        blueCumm[j] = blueCumm[j - 1] + blue[j];
                    }
                }
            }

            for (int j = 0; j <= i; j++)
            {
                if (j <= redMax)
                {
                    redCumm[j] = (int)Math.Round((redCumm[j] / ((double)BufferOfImage.GetLength(0) * BufferOfImage.GetLength(1))) * redMax, 3);
                }

                if (j <= greenMax)
                {
                    greenCumm[j] = (int)Math.Round((greenCumm[j] / ((double)BufferOfImage.GetLength(0) * BufferOfImage.GetLength(1))) * greenMax, 3);
                }

                if (j <= blueMax)
                {
                    blueCumm[j] = (int)Math.Round((blueCumm[j] / ((double)BufferOfImage.GetLength(0) * BufferOfImage.GetLength(1))) * blueMax, 3);
                }
            }

            this.NewBufferOfImage = new Color[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
            Bitmap newImg = new Bitmap(BufferOfImage.GetLength(0), BufferOfImage.GetLength(1));
            for (i = 0; i < BufferOfImage.GetLength(1); i++)
            {
                for (int j = 0; j < BufferOfImage.GetLength(0); j++)
                {
                    int newRed = (int)redCumm[BufferOfImage[j, i].R];
                    int newGreen = (int)redCumm[BufferOfImage[j, i].G];
                    int newBlue = (int)redCumm[BufferOfImage[j, i].B];
                    this.NewBufferOfImage[j, i] = Color.FromArgb(newRed, newGreen, newBlue);
                    newImg.SetPixel(j, i, Color.FromArgb(newRed, newGreen, newBlue));
                }
            }

            return newImg;
        }

        /// <summary>
        /// Gets the MAX color in picture .
        /// </summary>
        /// <param name="data">the array of accurance of certain color in image.</param>
        /// <returns>max color</returns>
        public long GetMaxColor(long[] data)
        {
            long max_color = 0;
            for (int i = 1; i < data.GetLength(0); i++)
            {
                if (data[i] > 0)
                {
                    max_color = i;
                }
            }

            return max_color;
        }

        /// <summary>
        /// Matchings this instance.
        /// </summary>
        /// <returns></returns>
        public Bitmap Matching()
        {
            return null;
        }
    }
}
